﻿using System;
using Microsoft.Win32;
using Neoseeker.NAMFox.Tests.Infrastructure;

namespace Neoseeker.NAMFox.Tests.Browsers
{
    /// <summary>
    /// Contains information on how to run NAMFox tests against Firefox.
    /// </summary>
    public class FirefoxConfiguration : BrowserConfiguration
    {
        private Version version;

        /// <summary>
        /// Initializes a new instance of the <see cref="FirefoxConfiguration"/> class.
        /// </summary>
        /// <param name="version">The version of Firefox to target.</param>
        public FirefoxConfiguration(Version version)
        {
            this.version = version;
        }

        /// <summary>
        /// Gets the relative file path to the JavaScript file that
        /// contains Firefox extensions to Selenium.
        /// </summary>
        public override string SeleniumExtensionsPath
        {
            get { return @"..\..\firefox\firefox-extensions.js"; }
        }

        /// <summary>
        /// Gets the start command for Firefox.
        /// </summary>
        /// <returns>The start command.</returns>
        public override string GetStartCommand()
        {
            return "*firefox " + this.FindBrowser();
        }

        private string FindBrowser()
        {
            using (var firefoxKey = Registry.LocalMachine.OpenSubKey(GetRootRegistryKey()))
            {
                FirefoxVersionKey targetKey = null;
                string targetVersion = String.Format("{0}.{1}", this.version.Major, this.version.Minor);

                string[] versions = firefoxKey.GetSubKeyNames();
                foreach (var version in versions)
                {
                    // Find the highest build that matches targetVersion
                    if (version.StartsWith(targetVersion))
                    {
                        FirefoxVersionKey firefoxVersionKey = FirefoxVersionKey.Parse(version);
                        if (targetKey == null || targetKey.Version < firefoxVersionKey.Version)
                        {
                            targetKey = firefoxVersionKey;
                        }
                    }
                }

                if (targetKey == null)
                {
                    throw new InvalidOperationException("Could not locate an installation of Firefox matching version " + this.version.ToString());
                }

                using (var versionKey = firefoxKey.OpenSubKey(targetKey.KeyName + "\\Main"))
                {
                    return versionKey.GetValue("PathToExe").ToString();
                }
            }
        }

        private static string GetRootRegistryKey()
        {
            // Since Firefox is a 32-bit application, we'll need
            // to find the correct root registry key depending
            // on what the architecture of the machine is.
            SafeNativeMethods.SYSTEM_INFO sysInfo = new SafeNativeMethods.SYSTEM_INFO();
            SafeNativeMethods.GetNativeSystemInfo(ref sysInfo);

            switch (sysInfo.uProcessorInfo.wProcessorArchitecture)
            {
                case SafeNativeMethods.ProcessorArchitecture.x86:
                    return @"SOFTWARE\Mozilla\Mozilla Firefox";
                case SafeNativeMethods.ProcessorArchitecture.IA64:
                case SafeNativeMethods.ProcessorArchitecture.AMD64:
                    return @"SOFTWARE\Wow6432Node\Mozilla\Mozilla Firefox";
                default:
                    throw new InvalidOperationException("Could not determine the root registry key for Mozilla Firefox.");
            }
        }

        private sealed class FirefoxVersionKey
        {
            public string KeyName;
            public Version Version;

            public static FirefoxVersionKey Parse(string keyName)
            {
                Version v = new Version(keyName.Split(' ')[0]);

                return new FirefoxVersionKey
                {
                    KeyName = keyName,
                    Version = v
                };
            }
        }
    }
}
